<?php
/**
 * Класс инициализации ресурсов, отвечающих за распределение прав доступа.
 */
class Workset_Application_Resource_Access
extends Zend_Application_Resource_ResourceAbstract
implements Workset_Acl_Options_Interface {
	/**
	 * Значения по умолчанию, которые можно переопределить в файле конфигурации.
	 * 
	 * @var array
	 */
	protected static $_aDefaultOptions = array(
		self::OP_USE_ASSERT				=> false,
		self::OP_USE_RATING				=> false,
		self::OP_ADMIN_GROUP_CODE		=> 'Administrators',
		self::OP_GUEST_ROLE_CODE		=> 'Guest',
		self::OP_REGISTERED_ROLE_CODE	=> 'Registered',
		self::OP_ADMIN_ID_LIST			=> array(-1),
		self::OP_REGISTRY_DB			=> 'dbAdapter',
		self::OP_REGISTRY_CACHE			=> 'cacheManager',
		self::OP_TABLE_GROUP			=> 't_access_group',
		self::OP_TABLE_ROLE				=> 't_access_role',
		self::OP_TABLE_R2G				=> 't_access_role2group',
		self::OP_TABLE_RESOURCE			=> 't_access_resource',
		self::OP_TABLE_PRIVILEGE		=> 't_access_privilege',
		self::OP_TABLE_P2R				=> 't_access_privilege2resource',
		self::OP_TABLE_RULE				=> 't_access_rule',
		self::OP_TABLE_U2G				=> 't_access_user2group',
		self::OP_FIELD_GROUP_ID			=> 'id',
		self::OP_FIELD_GROUP_CODE		=> 'code',
		self::OP_FIELD_ROLE_ID			=> 'id',
		self::OP_FIELD_ROLE_CODE		=> 'code',
		self::OP_FIELD_R2G_ROLE			=> 'role_id',
		self::OP_FIELD_R2G_GROUP		=> 'group_id',
		self::OP_FIELD_R2G_RATING		=> 'rating',
		self::OP_FIELD_RESOURCE_ID		=> 'id',
		self::OP_FIELD_RESOURCE_CODE	=> 'code',
		self::OP_FIELD_PRIVILEGE_ID     => 'id',
		self::OP_FIELD_PRIVILEGE_CODE   => 'code',
		self::OP_FIELD_P2R_PRIVILEGE	=> 'privilege_id',
		self::OP_FIELD_P2R_RESOURCE		=> 'resource_id',
		self::OP_FIELD_RULE_ALLOW		=> 'allow',
		self::OP_FIELD_RULE_ROLE		=> 'role_id',
		self::OP_FIELD_RULE_RESOURCE	=> 'resource_id',
		self::OP_FIELD_RULE_PRIVILEGE	=> 'privilege_id',
		self::OP_FIELD_RULE_ASSERT		=> 'assert',
		self::OP_FIELD_U2G_USER			=> 'user_id',
		self::OP_FIELD_U2G_GROUP		=> 'group_id',
	);

	/**
	 * @var Zend_Acl
	 */
	protected $_oAcl = null;

	/**
	 * @var Workset_Application_Resource_Access
	 */
	private static $_oInstance = null;

	/**
	 * Инициализация объекта данного класса.
	 * 
	 * @param array|null $options
	 */
	public function __construct($options = null) {
		// Вызываем родительский метод.
		parent::__construct($options);
		self::$_oInstance = $this;

		// Проверяем наличие всех необходимых параметров и выставляем значения
		// поумолчанию, в случае необходимости.
		foreach (array_keys(self::$_aDefaultOptions) as $sKey) {
			if (!isset($this->_options[$sKey])) {
				$this->_options[$sKey] = self::$_aDefaultOptions[$sKey];
			}

			// Приведение к нужному типу.
			switch (TRUE) {
				case is_string(self::$_aDefaultOptions[$sKey]):
					$this->_options[$sKey] = (string)$this->_options[$sKey];
					break;

				case is_array(self::$_aDefaultOptions[$sKey]):
					$this->_options[$sKey] = (array)$this->_options[$sKey];
					break;

				case is_bool(self::$_aDefaultOptions[$sKey]):
					$this->_options[$sKey] = $this->_options[$sKey] === true
						|| $this->_options[$sKey] == 1
						|| in_array(strtolower($this->_options[$sKey]),array('true','on'),true);
					break;
			}
		}
	}

	/**
	 * Инициализация объекта распределения прав доступа.
	 *
	 * @see library/Zend/Application/Resource/Zend_Application_Resource_Resource#init()
	 * @return Workset_Acl
	 */
	function init() {
		return $this->getAcl();
	}

	/**
	 * Получение объекта распределения прав доступа.
	 *
	 * @return Workset_Acl
	 */
	public function getAcl($bUpdateCache = false) {
		if ($this->_oAcl === null) {
			$aOptions = $this->getOptions();
			ksort($aOptions);
			$sCacheId = md5('ACL_OBJECT:'.serialize($aOptions));

			// Создаем объект Zend_Cache.
			$oCache = Zend_Registry::get($aOptions[self::OP_REGISTRY_CACHE])->getCache('default');

			// Если кэш отсутствует или выставлен флаг принудительного обновления.
			if ($bUpdateCache || !$this->_oAcl = $oCache->load($sCacheId)) {
				// Создаём экземпляр класса Zend_Acl (Workset_Acl).
				$this->_oAcl = new Workset_Acl();
				$this->_oAcl->setOptions($aOptions);
				$this->_oAcl->loadFromDb();

				// Сохраняем результат в кэше.
				$oCache->save($this->_oAcl,$sCacheId,array(),600);
			}
		}
		
		return $this->_oAcl;
	}

	/**
	 * Сброс кэша для данного ресурса.
	 */
	public static function resetCache() {
		if (self::$_oInstance) {
			self::$_oInstance->_oAcl = null;
			self::$_oInstance->getAcl(true);
		}
	}
}
